// 倒计时定时器模块 
// 功能特性：
// 1. 20秒倒计时，支持启动/暂停/停止控制 
// 2. 数码管十位/个位分离输出 
// 3. 状态机驱动设计 
// 4. 完全同步设计，消除亚稳态风险 
module Timer(
    input  logic       clk,       // 50MHz主时钟 
    input  logic       clk_1Hz,   // 1Hz分频时钟（需外部提供）
    input  logic       rst,       // 高电平复位（异步）
    input  logic       s3,        // 控制按钮（已消抖）
    output logic       counter_en, // 计数器使能信号 
    output logic [1:0] state_out, // 当前状态输出 
    output logic [4:0] ge,        // 个位数（BCD编码）
    output logic [4:0] shi        // 十位数（BCD编码）
);
 
// ================= 状态机定义 ================= 
typedef enum logic [1:0] {
    STOP  = 2'b01,  // 停止状态：初始状态，数值保持20 
    RUN   = 2'b10,  // 运行状态：倒计时进行中 
    PAUSE = 2'b00   // 暂停状态：保持当前数值 
} state_t;
 
// ================= 寄存器声明 ================= 
state_t current_state;  // 当前状态寄存器 
state_t next_state;     // 次态寄存器 
logic [4:0] count;      // 倒计时计数器（0-20）
logic clk_1Hz_prev;     // 1Hz时钟边沿检测寄存器 
 
// ================= 状态转移逻辑 ================= 
always_comb begin 
    case (current_state)
        STOP: begin 
            // 停止状态转换条件：
            // - 按下S3时进入运行状态 
            // - 保持当前计数值为20 
            next_state = (s3) ? RUN : STOP;
        end 
        
        RUN: begin 
            // 运行状态转换条件：
            // - 倒计时到0自动进入停止状态 
            // - 按下S3进入暂停状态 
            if (count == 0)         next_state = STOP;
            else if (s3)            next_state = PAUSE;
            else                    next_state = RUN;
        end 
        
        PAUSE: begin 
            // 暂停状态转换条件：
            // - 按下S3返回运行状态 
            next_state = (s3) ? RUN : PAUSE;
        end 
        
        default: next_state = STOP; // 默认状态保护 
    endcase 
end 
 
// ================= 状态寄存器更新 ================= 
always_ff @(posedge clk or posedge rst) begin 
    if (rst) begin 
        current_state <= STOP;      // 异步复位到停止状态 
    end else begin 
        current_state <= next_state; // 同步状态更新 
    end 
end 
 
// ================= 1Hz时钟边沿检测 ================= 
always_ff @(posedge clk) begin 
    clk_1Hz_prev <= clk_1Hz;  // 时钟延迟采样 
end 
wire clk_1Hz_rise = ~clk_1Hz_prev & clk_1Hz; // 上升沿检测 
 
// ================= 倒计时计数器逻辑 ================= 
always_ff @(posedge clk or posedge rst) begin 
    if (rst) begin 
        // 复位初始化 
        count <= 20; // 初始值设为20 
    end else if (next_state == STOP) begin 
        // 状态即将进入STOP时重置计数器（提前重置确保数值稳定）
        count <= 20;
    end else if (current_state == RUN) begin 
        // 运行状态处理 
        if (clk_1Hz_rise) begin 
            // 1Hz时钟上升沿触发递减 
            count <= (count > 0) ? count - 1 : 0;
        end 
    end 
    // 暂停状态(Pause)保持当前值（隐式处理）
end 
 
// ================= BCD数值分解逻辑 ================= 
always_comb begin 
    // 个位计算：对10取模 
    ge  = count % 10;  // 例：19 → 9 
    
    // 十位计算：整除10后取模（支持超过99的扩展）
    shi = (count / 10) % 10; // 例：19 → 1 
end 
 
// ================= 输出信号生成 ================= 
always_comb begin
    counter_en = (current_state == RUN); // 仅运行状态使能 
    state_out  = current_state;          // 状态直接输出 
end
 
// ================= 设计验证断言 ================= 
// synthesis translate_off 
initial begin 
    // 初始状态验证 
    assert (STOP == 2'b01) else $error("STOP状态编码错误");
    assert (RUN  == 2'b10) else $error("RUN状态编码错误");
    assert (PAUSE== 2'b00) else $error("PAUSE状态编码错误");
end 
 
// 运行时状态保护 
always @(posedge clk) begin 
    if (^current_state === 1'bx) begin 
        $error("状态机进入未知状态");
    end 
end 
// synthesis translate_on 
 
endmodule 